03.01 - Juego de la vida de Conway
Lenguajes Estructurados
Introducción
El Juego de la Vida es un autómata celular creado por John Horton Conway en 1970. Consiste en una cuadrícula de células que pueden estar vivas o muertas, y evoluciona según unas reglas muy simples. En cada turno, las células que están vivas pueden morir por sobrepoblación o por soledad, mientras que las células que están muertas pueden revivir si hay exactamente tres células vivas adyacentes. A pesar de su simplicidad, el Juego de la Vida puede generar patrones complejos y fascinantes.
En este ejemplo, implementaremos el Juego de la Vida en formato ASCII en C. El programa generará un tablero aleatorio de células vivas y muertas, lo imprimirá en la consola y lo actualizará según las reglas del juego.
Algoritmo
El algoritmo del Juego de la Vida se puede resumir en los siguientes pasos:
- Se genera un tablero aleatorio de células vivas y muertas.
- En cada turno, se cuenta el número de células vivas adyacentes a cada célula.
- Las células que están vivas pueden morir por sobrepoblación o por soledad, y las células que están muertas pueden revivir si hay exactamente tres células vivas adyacentes.
- Se actualiza el tablero según las células que han muerto o revivido.
Implementación en C
- Para implementar el Juego de la Vida en C, necesitaremos las siguientes bibliotecas:
- Para utilizar la función usleep() es necesario incluir la biblioteca unistd.h.
- Para generar números aleatorios, se debe incluir la biblioteca stdlib.h.
- Para utilizar los tipos de datos bool, true y false, se debe incluir la biblioteca stdbool.h.
- Para utilizar la función time() es necesario incluir la biblioteca time.h.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <time.h>
#include <unistd.h>
- Definir las constantes y variables globales Se deben definir las constantes ROWS y COLS para especificar el tamaño del tablero, y las variables globales board y new_board para almacenar el estado actual del tablero y el estado nuevo después de cada actualización.
#define ROWS 20
#define COLS 50
bool board[ROWS][COLS];
bool new_board[ROWS][COLS];
- Función para imprimir el tablero Crear una función print_board() que imprima el tablero en la consola.
void print_board() {
for(int i = 0; i < ROWS; i++) {
for(int j = 0; j < COLS; j++) {
if(board[i][j]) {
printf("*");
} else {
printf(" ");
}
}
printf("\n");
}
}
- Función para inicializar el tablero aleatoriamente La función init_board() debe inicializar cada celda del tablero aleatoriamente, utilizando la función rand(). En este ejemplo, se utilizará una semilla basada en la hora actual para generar valores pseudoaleatorios.
void init_board() {
srand(time(NULL));
for(int i = 0; i < ROWS; i++) {
for(int j = 0; j < COLS; j++) {
board[i][j] = rand() % 2;
}
}
}
- Función para contar células vivas adyacentes Se debe crear una función count_neighbors(row, col) que cuente el número de células vivas adyacentes a una célula dada en una posición (row, col) del tablero.
int count_neighbors(int row, int col) {
int count = 0;
for(int i = row - 1; i <= row + 1; i++) {
for(int j = col - 1; j <= col + 1; j++) {
if(i == row && j == col) {
continue;
}
if(i < 0 || i >= ROWS || j < 0 || j >= COLS) {
continue;
}
if(board[i][j]) {
count++;
}
}
}
return count;
}
- Función para actualizar el tablero
Se debe crear una función update_board() que actualice el tablero según las células que han muerto o revivido.
Para hacerlo, se debe:
- iterar sobre cada celda del tablero
- contar el número de células vivas adyacentes a cada celda
- aplicar las reglas del Juego de la Vida para determinar si la célula debe morir o revivir.
void update_board() {
for(int i = 0; i < ROWS; i++) {
for(int j = 0; j < COLS; j++) {
int neighbors = count_neighbors(i, j);
if(board[i][j]) {
if(neighbors < 2 || neighbors > 3) {
new_board[i][j] = false;
} else {
new_board[i][j] = true;
}
} else {
if(neighbors == 3) {
new_board[i][j] = true;
} else {
new_board[i][j] = false;
}
}
}
}
for(int i = 0; i < ROWS; i++) {
for(int j = 0; j < COLS; j++) {
board[i][j] = new_board[i][j];
}
}
}
- Función principal Por último, se debe crear la función principal main() que inicializa el tablero aleatoriamente, entra en un bucle infinito en el que se imprime el tablero, se actualiza el tablero y se espera un corto período de tiempo antes de repetir el proceso.
int main() {
init_board();
while(true) {
system("cls"); // Limpia la pantalla en sistemas Windows
print_board();
update_board();
usleep(100000); // Espera 100 milisegundos
}
return 0;
}